/**
 * Title:		Frog.java
 * Description: This class implements the Frog object.
 * Also this class is wrapper class of FrogFactory.java. The Frog logic is 
 * implemented in FrogFactory.java.
 * In this class, the coordination system complies with KFrog Language.
 * 
 * @version		1.0 May 2009
 * @author		Hidemitsu Izawa (hi2136@columbia.edu)
 */

package kfrog;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Frog implements Runnable{
	
	private Pond pond;
	private LinkedList<String> commandList;
	private FrogFactory frog;
	private int frogSize=20;//default=6
	private int frogID = 1;
	private boolean isDisplayDebugMessage;
	private boolean active;
	
	/**
	 * Frog initial action
	 */
	public Frog(Pond pond){
		this.pond = pond;
		/** get frogID */
		this.frogID = pond.getNumberOfFrog();
		commandList = new LinkedList<String>();
		commandList.add(Const.CREATEFROG);//create frog
		commandList.add(Const.CENTER);//move center
		this.isDisplayDebugMessage = 
			KFrogMain.debug || KFrogMain.test || KFrogMain.testSemantics;
		this.active = true;
	}
	
	public Frog(Pond pond, int frogID){
		this.pond = pond;
		this.frogID = frogID;
		commandList = new LinkedList<String>();
		commandList.add(Const.CREATEFROG);//create frog
		commandList.add(Const.CENTER);//move center
		this.isDisplayDebugMessage = 
			KFrogMain.debug || KFrogMain.test || KFrogMain.testSemantics;
		this.active = true;
	}
	
	/**
	 * methods
	 */
	
	/** isActive */
	public boolean isActive(){
		return this.active;
	}
	
	
	/** setActive */
	public void setActive(){
		this.active = true;
	}
	
	
	/** setInactive */
	public void setInactive(){
		this.active = false;
	}
	
	
	/** set frog speed */
	public void speed(int speed){
		int interval;
		if(speed==1){
			interval = Const.SPEED1;
		}
		else if(speed==2){
			interval = Const.SPEED2;
		}
		else if(speed==3){
			interval = Const.SPEED3;
		}
		else if(speed==4){
			interval = Const.SPEED4;
		}
		else if(speed==5){
			interval = Const.SPEED5;
		}
		else{
			interval = Const.SPEED3;
		}
		commandList.add(Const.SPEED + " " + interval);
	}
	
	
	/** forward command */
	public void forward(double distance){
		commandList.add(Const.FORWARD + " " + distance);
	}
	
	
	/** turnleft command */
	public void turnleft(double angle){
		commandList.add(Const.TURNLEFT + " " + angle);
	}
	
	
	/** turnright command */
	public void turnright(double angle){
		commandList.add(Const.TURNRIGHT + " " + angle);
	}
	
	
	/** leftcurve command */
	public void leftcurve(double radius, double angle){
		commandList.add(Const.LEFTCURVE + " " + radius + " " + angle);
	}
	
	
	/** rightcurve command */
	public void rightcurve(double radius, double angle){
		commandList.add(Const.RIGHTCURVE + " " + radius + " " + angle);
	}
	
	
	/** goto command in KFrog(in Java, we cannot implement goto method, 
	 * because it is the identifier of the Java convention)
	 */
	public void move(double x, double y){
		commandList.add(Const.GOTO + " " + x + " " + y);
	}
	
	
	/** startdraw command*/
	public void startdraw(){
		commandList.add(Const.STARTDRAW);
	}
	
	
	/** stopdraw command*/
	public void stopdraw(){
		commandList.add(Const.STOPDRAW);
	}
	
	
	/** frogcolor command */
	public void frogcolor(String color){
		commandList.add(Const.FROGCOLOR + " " + color);
	}
	
	
	/** center command */
	public void center(){
		commandList.add(Const.CENTER);
	}
	
	
	/** sleep command 
	 * @param duration duration of the sleep time in milliseconds*/
	public void sleep(int duration){
		commandList.add(Const.SLEEP + " " + duration);
	}
	
	
	/** random CAUTION: this method is not added commandList, 
	 * because it can be executed promptly.
	 * @param n min number for random
	 * @param m max number for random
	 * @return
	 */
    public int random(int n, int m){
    	return (int)Math.floor(Math.random() * (m - n + 1)) + n;
    }
	
    
    /** run thread */
	public void run(){
		executeCommandList();
		/** debug-output */
		if(isDisplayDebugMessage){
			System.out.println(this.frogID + " }");//output for "new Frog {"
			/** in debugging, close window (exit(0)) after all threads 
			 * have finished execution.
			 */
			this.pond.terminateNotification();
		}
	}
	
	
	/** inside the run() */
	private void executeCommandList(){
		Iterator<String> ite = commandList.iterator();
		while(ite.hasNext()){
			String oneCommand = ite.next();
			StringTokenizer st = new StringTokenizer(oneCommand," ");
			String commandName = st.nextToken();
			
			if(commandName.equals(Const.CREATEFROG)){
				frog = new FrogFactory(pond,frogSize,this.frogID);
			}
			else if(commandName.equals(Const.GOTO)){
				double x = Double.parseDouble(st.nextToken());
				double y = Double.parseDouble(st.nextToken());
				frog.move(x, pond.getHeight() - y,true); //convert coordinate
			}
			else if(commandName.equals(Const.FORWARD)){
				double distance = Double.parseDouble(st.nextToken());
				frog.forward(distance);
			}
			else if(commandName.equals(Const.TURNLEFT)){
				double angle = Double.parseDouble(st.nextToken());
				frog.turnleft(angle);
			}
			else if(commandName.equals(Const.TURNRIGHT)){
				double angle = Double.parseDouble(st.nextToken());
				frog.turnright(angle);
			}
			else if(commandName.equals(Const.STARTDRAW)){
				frog.penDown();
			}
			else if(commandName.equals(Const.STOPDRAW)){
				frog.penUp();
			}
			else if(commandName.equals(Const.FROGCOLOR)){
				String color = st.nextToken();
				frog.setColor(color);
			}
			else if(commandName.equals(Const.SPEED)){
				int speed = Integer.parseInt(st.nextToken());
				frog.setFrogSpeed(speed);
			}
			else if(commandName.equals(Const.CENTER)){
				frog.moveCenter();
			}
			else if(commandName.equals(Const.LEFTCURVE)){
				double radius = Double.parseDouble(st.nextToken());
				double angle = Double.parseDouble(st.nextToken());
				frog.leftcurve(radius, angle);
			}
			else if(commandName.equals(Const.RIGHTCURVE)){
				double radius = Double.parseDouble(st.nextToken());
				double angle = Double.parseDouble(st.nextToken());
				frog.rightcurve(radius, angle);
			}
			else if(commandName.equals(Const.SLEEP)){
				int duration = Integer.parseInt(st.nextToken());
				frog.sleep(duration);
			}
			else{
				System.err.println("ERROR: no such command. in Frog.java");
			}
		}
	}
}
